﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Collections;
using System.Reflection;

namespace iBing.Common.Common
{
    public class ObjectArrayToDataTable
    {
        #region 构造函数
        public ObjectArrayToDataTable()
  {
   //
   // TODO: 在此处添加构造函数逻辑
   //
  }
        #endregion
        
        #region 属性设置
        private bool _ColumnFromProperty = true;
        /// <summary>
        /// DataTable列是否根据对象的属性生成;默认为True,如果为False则由对象的字段生成
        /// </summary>
        public bool ColumnFromProperty
        {
        get{return _ColumnFromProperty;}
        set{_ColumnFromProperty=value;}
        }

        private string _PointString = ".";
        /// <summary>
        /// 点号的替换符号
        /// </summary>
        public string PointString
        {
        get{return _PointString;}
        set{_PointString = value;}
        }
        #endregion
    
        #region 公共方法

  /// <summary>
  /// 对象数组转换为DataTable
  /// </summary>
  /// <param name="objArry">对象数组</param>
  /// <returns></returns>
  public DataTable ArrayToDataTable(object[] objArry)
  {
   if(objArry.Length <= 0)
   {
    return null;
   }
   Type objType = objArry[0].GetType();
   DataTable dt = CreateDataTable(objType);
   dt = FillDataTable(dt, objArry);
   return dt;
  }

  #endregion

        #region 私有方法

  /// <summary>
  /// 创建DataTable
  /// </summary>
  /// <param name="objType"></param>
  /// <returns></returns>
  private DataTable CreateDataTable(Type objType)
  {
   DataTable dt = new DataTable();
   ArrayList[] myList;
   if(this.ColumnFromProperty)
   {
    myList = GetPropertiesInfo(objType, "");
   }
   else
   {
    myList = GetFieldsInfo(objType, "");
   }
   for(int i=0; i<myList[0].Count; i++)
   {
    DataColumn dColumn = new DataColumn(myList[0][i].ToString(), System.Type.GetType(myList[1][i].ToString()));
    dt.Columns.Add(dColumn);   
   }
   return dt;
  }


  private DataTable FillDataTable(DataTable dt, object[] objArry)
  {
   DataColumnCollection dtColumns = dt.Columns;
   Type objType = objArry[0].GetType();
   foreach (object obj in objArry)
   {
    DataRow dRow = dt.NewRow();
    for (int i = 0; i < dtColumns.Count; i++)
    {
     if(this.ColumnFromProperty)
     {
      dRow[i] = GetPropertyByPath(dtColumns[i].ColumnName, obj);
     }
     else
     {
      dRow[i] = GetFieldByPath(dtColumns[i].ColumnName, obj);
     }
    }
    dt.Rows.Add(dRow);
   }
   return dt;
  }


  /// <summary>
  /// 获取对象的字段信息
  /// </summary>
  /// <param name="myType">对象的类型</param>
  /// <param name="UpName">上级名称</param>
  /// <returns></returns>
  private ArrayList[] GetFieldsInfo(Type myType, string UpName)
  {
   ArrayList[] myList = new ArrayList[2];
   myList[0] = new ArrayList();
   myList[1] = new ArrayList();
   FieldInfo[] myFieldInfo = myType.GetFields();
   string strType = "";
   string strName = "";
   foreach (FieldInfo myField in myFieldInfo)
   {
    strName = (UpName == "")?myField.Name:UpName + this.PointString + myField.Name;
    strType = myField.FieldType.ToString();
    if(strType.Length > 2 && strType.Substring(strType.Length - 2, 2) != "[]")
    {
     if(strType.Length > 6 && strType.Substring(0, 6) == "System")
     {
      myList[0].Add(strName);
      myList[1].Add(myField.FieldType.ToString());
     }
     else
     {
      ArrayList[] aryOther = GetFieldsInfo(myField.FieldType, strName);
      for(int i=0; i<aryOther[0].Count; i++)
      {
       myList[0].Add(aryOther[0][i]);
       myList[1].Add(aryOther[1][i]);
      }
     }
    }
   }
   return myList;
  }


  /// <summary>
  /// 获取对象的属性信息
  /// </summary>
  /// <param name="myType">对象的类型</param>
  /// <param name="UpName">上级名称</param>
  /// <returns></returns>
  private ArrayList[] GetPropertiesInfo(Type myType, string UpName)
  {
   ArrayList[] myList = new ArrayList[2];
   myList[0] = new ArrayList();
   myList[1] = new ArrayList();
   PropertyInfo[] myPropertyInfo = myType.GetProperties();
   string strType = "";
   string strName = "";
   foreach (PropertyInfo myProperty in myPropertyInfo)
   {
    strName = (UpName == "")?myProperty.Name:UpName + this.PointString + myProperty.Name;
    strType = myProperty.PropertyType.ToString();
    if(strType.Length > 2 && strType.Substring(strType.Length - 2, 2) != "[]")
    {
     if(strType.Length > 6 && strType.Substring(0, 6) == "System")
     {
      myList[0].Add(strName);
      myList[1].Add(strType);
     }
     else
     {
      ArrayList[] aryOther = GetPropertiesInfo(myProperty.PropertyType, strName);
      for(int i=0; i<aryOther[0].Count; i++)
      {
       myList[0].Add(aryOther[0][i]);
       myList[1].Add(aryOther[1][i]);
      }
     }
    }
   }
   return myList;
  }


  private object GetFieldByPath(string strPath, object obj)
  {
   object objRet;
   string[] aryPaths;
   string strOtherPath = "";
   Type objType = obj.GetType();
   if(strPath.IndexOf(this.PointString) < 0)
   {
    objRet = objType.InvokeMember(strPath, BindingFlags.GetField, null, obj, null);
   }
   else
   {
    aryPaths = SplitPage(strPath, this.PointString);
    for(int i=1; i<aryPaths.Length; i++)
    {
     if(strOtherPath!=""){strOtherPath += this.PointString;}
     strOtherPath += aryPaths[i];
    }
    object objTemp = objType.InvokeMember(aryPaths[0], BindingFlags.GetField, null, obj, null);
    objRet = GetFieldByPath(strOtherPath, objTemp);
   }
   return objRet;   
  }


  private object GetPropertyByPath(string strPath, object obj)
  {
   object objRet;
   string[] aryPaths;
   string strOtherPath = "";
   Type objType = obj.GetType();
   if(strPath.IndexOf(this.PointString) < 0)
   {
    objRet = objType.InvokeMember(strPath, BindingFlags.GetProperty, null, obj, null);
   }
   else
   {
    aryPaths = SplitPage(strPath, this.PointString);
    for(int i=1; i<aryPaths.Length; i++)
    {
     if(strOtherPath!=""){strOtherPath += this.PointString;}
     strOtherPath += aryPaths[i];
    }
    object objTemp = objType.InvokeMember(aryPaths[0], BindingFlags.GetProperty, null, obj, null);
    objRet = GetFieldByPath(strOtherPath, objTemp);
   }
   return objRet;   
  }

 

  /// <summary>
  /// 根据指定的标记符，分隔字符串，并返回字符数组
  /// </summary>
  /// <param name="source">要分隔的字符串</param>
  /// <param name="split">分隔标记符字符串</param>
  public static string[] SplitPage(string source,string split)
  {   
   int len = split.Length;      
   ArrayList al = new ArrayList();
   int start = 0; //开始位置
   int j = -1; //匹配索引位置
   while(true)
   {
    j = source.IndexOf(split,start);
    if(j > -1)
    { 
     al.Add(source.Substring(start,j-start));
     int s = j-start;    
     start = j+len;     
    }
    else
    {
     al.Add(source.Substring(start));
     break;
    }
   }
   string[] result;
   if(al.Count == 0)
   {
    string[] r = new string[1];
    r[0] = source;
    result = r;
   }
   else
   {
    string[] r = new string[al.Count];
    for(int i = 0; i < al.Count; i++)
    {
     r[i] = al[i].ToString();
    }
    result = r;
   }
   return result;
  }

  #endregion

 }

}
